//=================================================================================================
// DESC: easy access of parallel port
// AUTHOR: wiRe (http://w1r3.de/)
// DATE: 07/04/2006
//
// Copyright (c)2006 wiRe
//=================================================================================================
#include <assert.h>
#include "pport.h"


//-------------------------------------------------------------------------------------------------
//prototypes of DLL inpout32 functions, also needs inpout32.lib
//-------------------------------------------------------------------------------------------------
short _stdcall Inp32(short PortAddress);
void _stdcall Out32(short PortAddress, short data);




//-------------------------------------------------------------------------------------------------
short PPort::DefaultBasePortList[] = {0x3BC, 0x378, 0x278, -1};


//-------------------------------------------------------------------------------------------------
PPort::PinDesc PPort::PinLookUp[] =  //port=0: data, =1:status, =2:control
{
  {0,0,false},    //pin 0 doesnt exist
  {2,1<<0,true},
  {0,1<<0,false}, {0,1<<1,false}, {0,1<<2,false}, {0,1<<3,false},
  {0,1<<4,false}, {0,1<<5,false}, {0,1<<6,false}, {0,1<<7,false},
  {1,1<<6,false}, {1,1<<7,true},  {1,1<<5,false}, {1,1<<4,false},
  {2,1<<1,true},  {1,1<<3,false}, {2,1<<2,false}, {2,1<<3,true},
  {-1,-1,false}   //terminator
};




//-------------------------------------------------------------------------------------------------
bool PPort::init(short baseport)
{
  if(baseport < 0)  //autodetect?
  {
    for(short n=0; DefaultBasePortList[n] >= 0; n++)
    {
      if(init(DefaultBasePortList[n])) return true;
    }
    return false;
  }


  short bak = Inp32(baseport);

  do {
    Out32(baseport, 0xAA);
    if(Inp32(baseport) != 0xAA) break;
    Out32(baseport, 0x54);
    if(Inp32(baseport) != 0x54) break;

    BasePort = baseport;
    for(short n=0; PinLookUp[n].bit >= 0; n++) clr(n);  //clear all pins
    return true;
  } while(0);

  Out32(baseport, bak);
  return false;
}


//-------------------------------------------------------------------------------------------------
bool PPort::get(short pin)
{
  assert(BasePort >= 0);
  short b = Inp32(BasePort+PinLookUp[pin].port);
  bool s = ((b & PinLookUp[pin].bit) != 0);
  if(PinLookUp[pin].inv) s = s?false:true;
  return s;
}


//-------------------------------------------------------------------------------------------------
void PPort::set(short pin, bool state)
{
  assert(BasePort >= 0);
  short b = Inp32(BasePort+PinLookUp[pin].port);
  if(PinLookUp[pin].inv) state = state?false:true;
  if(state) b |= PinLookUp[pin].bit; else b &= (255-PinLookUp[pin].bit);
  Out32(BasePort+PinLookUp[pin].port, b);
}


//-------------------------------------------------------------------------------------------------
void PPort::clr(short pin)
{
  set(pin, false);
}


//-------------------------------------------------------------------------------------------------
bool PPort::toggle(short pin)
{
  bool s = get(pin)?false:true;
  set(pin, s);
  return s;
}
